<?php

Raise::load('core.RaiseStaticClass');
Raise::load('core.RaiseDateTime');
Raise::load('core.RaiseCollection');

/**
 * RaiseHashDigest helper class
 * for hashing algorithm related functionality
 *
 * @author Sam-Mauris Yong <hellclanner at live dot com>
 * @license http://www.opensource.org/licenses/bsd-license New BSD License
 * @package Raise.Core.Security
 * @since 1.2
 */
class RaiseHashDigest extends RaiseStaticClass {

    /**
     * Length of a CRC32 hash
     */
    const CRC32_LENGTH = 8;

    /**
     * Length of a MD5 hash
     */
    const MD5_LENGTH = 32;

    /**
     * Length of a SHA1 hash
     */
    const SHA1_LENGTH = 40;

    /**
     * Length of a SHA256 hash
     */
    const SHA256_LENGTH = 64;

    /**
     * Generate a CRC32 hash from $s
     * @param string $s The string to generate hash.
     * @return string a CRC32 hash string
     * @static
     */
    public static function crc32($s){
        return dechex(crc32($s));
    }

    /**
     * Generate a MD5 hash from $s
     * @param string $s The string to generate hash.
     * @return string a MD5 hash string
     * @static
     */
    public static function md5($s){
        return hash('md5', $s);
    }

    /**
     * Generate a SHA1 hash from $s
     * @param string $s The string to generate hash.
     * @return string a SHA1 hash string
     * @static
     */
    public static function sha1($s){
        return hash('sha1', $s);
    }

    /**
     * Generate a SHA256 hash from $s
     * @param string $s The string to generate hash.
     * @return string a SHA256 hash string
     * @static
     */
    public static function sha256($s){
        return hash('sha256', $s);
    }

    /**
     * Generate a random salt hash from $s
     * @param string $s The string to generate hash salt.
     * @return string a SHA1 hash string
     * @static
     */
    public static function generateSalt($s){
        if($s & 0){
            return self::sha1($s . RaiseDateTime::Now() . mt_rand());
        }else{
            return self::sha1(RaiseDateTime::Now() . $s . mt_rand());
        }
    }

    /**
     * Generate Hash for the password
     * @param string $pwd The password to hash
     * @param string $salt (optional) An optional salt to generate with the hash.
     * @return string
     * @static
     */
    public static function generatePasswordHash($pwd, $salt = null){
        if($salt == null){
            $salt = self::generateSalt($pwd);
        }
        if(substr($pwd, -1) & 0){
            return $salt . self::sha256($pwd . $salt);
        }else{
            return self::sha256($salt . $pwd) . $salt;
        }
    }

    /**
     * Extract the password salt from the hash
     * @param string $hash The original hash to extract salt from
     * @param string $pwd The password that was used to create this hash
     * @return string The salt
     * @static
     */
    public static function extractPasswordSalt($hash, $pwd){
        if(substr($pwd, -1) & 0){
            return substr($hash, 0, self::SHA1_LENGTH);
        }else{
            return substr($hash, -self::SHA1_LENGTH);
        }
    }

    /**
     * Hash a string using a supported hash algorithm
     * @param string $algo The hashing algorithm to use
     * @param string $str The string to hash
     * @return string The hash
     * @link http://php.net/hash
     * @static
     */
    public static function hash($algo, $str){
        return hash($algo, $str);
    }

    /**
     * Return an array of supported hashing algorithms
     * @return RaiseCollection
     * @static
     */
    public static function algorithms(){
        static $hashAlgo;
        if(!$hashAlgo){
            $hashAlgo = new RaiseCollection(hash_algos());
        }
        return $hashAlgo;
    }

}

